import './PianoWaterfallGame.css'
import {useEffect, useMemo, useRef, useState} from "react";
import {loadPianoSheet, Piano, PianoNote, PianoSheet} from "../../services/Piano.ts";
import {useWindowSize} from "react-use";
import * as Tone from "tone";
import {AppCameraView} from "../CameraView/CameraView.tsx";
import {AppPianoKey} from "../PianoKey/PianoKey.tsx";
import {PianoWaterfall} from "../PianoWaterfall/PianoWaterfall.tsx";
import {PianoKeyboardElement} from "../PianoKey/PianoKeyContext.ts";


function calculatePianoKeyboardHeight(screenHeight: number) {
    // 琴键区域占屏幕高度的 30%, 最小不超过 180px, 最大不超过 300px

    let keyboardHeight = screenHeight * 0.3;

    if (keyboardHeight < 180) {
        keyboardHeight = 180;
    } else if (keyboardHeight > 300) {
        keyboardHeight = 300;
    }

    return keyboardHeight;
}

let playMusic = false;


export function PianoWaterfallGame() {

    const pianoWhiteKeyWidth = useMemo(() => 50, [])

    const pianoBlackKeyWidth = useMemo(() => 33, [])

    const pianoKeyboardWidth = useMemo(() => {
        return pianoWhiteKeyWidth * PianoKeyboardElement.WHITE_KEY_NUM
    }, [pianoWhiteKeyWidth]);

    const pianoRef = useRef<Piano>();

    const pianoSheetRef = useRef<PianoSheet>();

    const startTimeRef = useRef<number>(0);

    const [startGame, setStartGame] = useState<boolean>(false);

    // 监听屏幕尺寸变化重新渲染琴键
    const {height} = useWindowSize();

    // 计算琴键的高度
    const pianoKeyboardHeight = useMemo(() => {
        return calculatePianoKeyboardHeight(height);
    }, [height]);

    useEffect(() => {
        // 创建 Piano 对象
        Piano.create().then(piano => {
            pianoRef.current = piano;

            loadPianoSheet("test").then(sheet => {
                pianoSheetRef.current = sheet;

                startTimeRef.current = Tone.now();
                setStartGame(true);

                if (!playMusic) {
                    playMusic = true;
                    // piano.playPianoSheet(sheet, startTimeRef.current);
                }
            });
        });
    }, []);

    const [attackedNotes, setAttackedNotes] = useState<PianoNote[]>([]);

    const onNoteAttacked = (notes: PianoNote[]) => {
        setAttackedNotes(notes);
    }

    const onNoteTriggered = (notes: PianoNote[]) => {
        if (pianoRef.current) {
            for (const note of notes) {
                pianoRef.current.triggerAttackRelease(note.name, note.duration);
            }

        } else {
            console.warn("cannot attack keys " + notes + ", pianoRef not loaded yet.")
        }
    }

    const onAttackNote = (note: string) => {
        if (pianoRef.current) {
            pianoRef.current.triggerAttack(note);
        } else {
            console.warn("cannot attack key " + note + ", pianoRef not loaded yet.")
        }
    }

    const onReleaseNote = (note: string) => {
        if (pianoRef.current) {
            pianoRef.current.triggerRelease(note);
        } else {
            console.warn("cannot release key " + note + ", pianoRef not loaded yet.")
        }
    }

    return <AppCameraView sceneWidth={pianoKeyboardWidth}>
        {
            (startGame && pianoSheetRef.current) ?
                <>
                    <AppPianoKey
                        whiteKeyWidth={pianoWhiteKeyWidth}
                        blackKeyWidth={pianoBlackKeyWidth}
                        height={pianoKeyboardHeight}
                        attackedNotes={attackedNotes}
                        onTriggerAttack={onAttackNote}
                        onTriggerRelease={onReleaseNote}
                        topArea={
                            <PianoWaterfall
                                pianoSheet={pianoSheetRef.current}
                                startTimeSeconds={startTimeRef.current}
                                onNoteAttacked={onNoteAttacked}
                                onNoteTriggered={onNoteTriggered}
                            >
                            </PianoWaterfall>
                        }
                    >
                    </AppPianoKey>
                </>
                :
                <></>
        }
    </AppCameraView>
}